package com.auditlog.sql.runner;

import cn.hutool.core.util.StrUtil;
import com.auditlog.datasource.StatementProxy;
import com.auditlog.datasource.db.SqlType;
import com.auditlog.sql.wrapper.UpdateDeParserWrapper;
import com.auditlog.datasource.struct.RecordImage;
import com.auditlog.datasource.struct.StatementMetaData;
import com.auditlog.datasource.struct.TableRecord;
import com.auditlog.util.IndexUtils;
import lombok.extern.slf4j.Slf4j;
import net.sf.jsqlparser.statement.update.Update;

import java.util.List;

/**
 * @author Zhiyang.Zhang
 * @version 1.0
 * @date 2022/10/24 15:38
 */
@Slf4j
public class UpdateSqlRunner<T extends java.sql.Statement> extends AbstractSqlRunner<T, Update> {

    public UpdateSqlRunner(StatementProxy<T> statementProxy, Update update) {
        super(statementProxy, update);
    }


    @Override
    public RecordImage beforeImage() throws Exception {
        RecordImage.RecordImageBuilder recordImageBuilder = RecordImage.builder();
        String alias = StrUtil.isNotBlank(this.getAlias()) ? this.getAlias() : this.getTableName();
        // 获取带别名的列名
        List<String> allColumnNames = this.getTableMeta().getColumnNamesByOrder(alias);
        List<String> primaryKeyWithAlias = this.getTableMeta().getPrimaryKeyWithAlias(alias, true);
        recordImageBuilder
                .allColumnsWithAlias(allColumnNames)
                .tableMeta(this.getTableMeta())
                .pkColumnsName(primaryKeyWithAlias)
                .tableName(this.getTableName())
                .sqlType(SqlType.UPDATE)
                .alias(alias);
        StatementMetaData metaData = this.getMetaData(this.getStatement());
        PlaceHolderSqlContext sqlContext = this.getCurrentSqlContext(metaData.getTableRecordsSql(), metaData.getPlaceHolderIndex(), true);
        List<List<Object>> result = this.executeParametersHolderSqlWithLockTable(sqlContext);
        List<Integer> indexList = IndexUtils.getIndexList(primaryKeyWithAlias, allColumnNames);
        List<List<Object>> indexValue4List = this.getIndexValue4List(result, indexList, false);
        TableRecord tableRecord = this.buildTableRecord(result, primaryKeyWithAlias, allColumnNames);
        return recordImageBuilder.beforeRecord(tableRecord).possibleUpdateOrDeletePks(indexValue4List).build();
    }

    @Override
    public RecordImage afterImage(RecordImage beforeRecordImage) throws Exception {
        this.handleUpdateAfterRecordImage(beforeRecordImage);
        return beforeRecordImage;
    }

    @Override
    public StatementMetaData getMetaData(Update statement) {
        UpdateDeParserWrapper updateDeParserWrapper = new UpdateDeParserWrapper();
        // 这里为了防止update join时两表有相同的字段，所以没有别名时，用表名作为别名
        List<String> columnNamesByOrder = this.getTableMeta().getColumnNamesByOrder(StrUtil.isNotBlank(this.getAlias()) ? this.getAlias() : this.getTableName());
        String sql = updateDeParserWrapper.deSelectParse(this.getStatement(), columnNamesByOrder);
        List<Integer> validPalceholderIndex = updateDeParserWrapper.getValidPalceholderIndex();
        return StatementMetaData.builder()
                .tableRecordsSql(sql)
                .sqlType(SqlType.UPDATE)
                .placeHolderIndex(validPalceholderIndex)
                .tableName(this.getTableName())
                .sqlRunner(this)
                .build();
    }
}
